package cn.fintecher.pangolin.service.manage.service;

import cn.fintecher.pangolin.common.enums.BaseSelect;
import cn.fintecher.pangolin.common.enums.BaseStatus;
import cn.fintecher.pangolin.common.enums.DepartmentType;
import cn.fintecher.pangolin.common.enums.StrategyDistributeType;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.DepartmentModel;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.BeanUtils;
import cn.fintecher.pangolin.common.utils.ShortUUID;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.CollectorModel;
import cn.fintecher.pangolin.entity.elastic.Strategy;
import cn.fintecher.pangolin.entity.mysql.Department;
import cn.fintecher.pangolin.entity.mysql.QDepartment;
import cn.fintecher.pangolin.entity.mysql.QUser;
import cn.fintecher.pangolin.service.manage.elastic.StrategyElastic;
import cn.fintecher.pangolin.service.manage.repository.DepartmentRepository;
import cn.fintecher.pangolin.service.manage.repository.UserRepository;
import cn.fintecher.pangolin.service.manage.request.AddDepartmentRequest;
import cn.fintecher.pangolin.service.manage.request.ModifyDepartmentRequest;
import cn.fintecher.pangolin.service.manage.response.DepartmentResponse;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.collections4.IterableUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 16:54 2019/8/14
 */

@Service("departmentService")
@Transactional(rollbackFor = Exception.class)
public class DepartmentService {
    @Autowired
    private BaseService baseService;

    @Autowired
    private DepartmentRepository departmentRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private StrategyElastic strategyElastic;

    /**
     * 新增部门
     */
    public void addDepartment(AddDepartmentRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        QDepartment qDepartment = QDepartment.department;
        boolean b = departmentRepository.exists(qDepartment.name.eq(request.getName()));
        if (b) {
            throw new BadRequestException(null, "department", "department.is.repeat");
        }
        Department parent = departmentRepository.findById(request.getParentId()).orElseThrow(() -> new BadRequestException(null, "department", "department.parent.is.null"));
        Department department = new Department();
        BeanUtils.copyPropertiesIgnoreNull(request, department);
        department.setLevel(parent.getLevel() + 1);
        department.setDepartCode(parent.getDepartCode() + "_" + ShortUUID.generateShortUuid());
        department.setIsSystem(BaseSelect.NO);
        department.process(userModel.getId(), ZWDateUtil.getNowDateTime(), true);
        departmentRepository.save(department);
    }

    /**
     * 修改部门
     */
    public void modifyDepartment(ModifyDepartmentRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Department department = departmentRepository.findById(request.getDepartId()).orElseThrow(() -> new BadRequestException(null, "department", "department.is.null"));
        if (department.getIsSystem().equals(BaseSelect.YES)) {
            throw new BadRequestException(null, "department", "system.cant.modify");
        }
        QDepartment qDepartment = QDepartment.department;
        if (!Objects.equals(request.getParentId(), department.getParentId())) { //修改父级机构
            boolean b1 = departmentRepository.exists(qDepartment.parentId.eq(department.getId()));
            if (b1) {
                throw new BadRequestException(null, "department", "department.children.not.null");
            }
            boolean b2 = userRepository.exists(QUser.user.department.id.eq(department.getId()));
            if (b2) {
                throw new BadRequestException(null, "department", "department.user.not.null");
            }
            Department parent = departmentRepository.findById(request.getParentId()).orElseThrow(() -> new BadRequestException(null, "department", "department.parent.is.null"));
            department.setDepartCode(parent.getDepartCode() + "_" + ShortUUID.generateShortUuid());
            department.setLevel(parent.getLevel() + 1);
        }
        if (!Objects.equals(request.getName(), department.getName())) { //修改名称
            boolean b3 = departmentRepository.exists(qDepartment.name.eq(request.getName()).and(qDepartment.name.ne(department.getName())));
            if (b3) {
                throw new BadRequestException(null, "department", "department.is.repeat");
            }
        }
        //修改策略中的部门
        if (!request.getName().equals(department.getName())) {
            BoolQueryBuilder builder = new BoolQueryBuilder();
            builder.must(QueryBuilders.matchPhraseQuery("type.keyword", StrategyDistributeType.DEPARTMENT.name()));
            Iterable<Strategy> iterable = strategyElastic.search(builder);
            List<Strategy> list = IterableUtils.toList(iterable);
            if (!list.isEmpty()) {
                for (Strategy strategy : list) {
                    List<CollectorModel> models = strategy.getModels();
                    for (CollectorModel model : models) {
                        if (model.getId().equals(department.getId())) {
                            model.setName(request.getName());
                        }
                    }
                }
                strategyElastic.saveAll(list);
            }
        }
        BeanUtils.copyPropertiesIgnoreNull(request, department);
        department.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
        departmentRepository.save(department);
    }

    /**
     * 删除部门
     */
    public void deleteDepartment(String departId) {
        Department department = departmentRepository.findById(departId).orElseThrow(() -> new BadRequestException(null, "department", "department.is.null"));
        if (department.getIsSystem().equals(BaseSelect.YES)) {
            throw new BadRequestException(null, "department", "system.cant.delete");
        }
        boolean b = userRepository.exists(QUser.user.department.id.eq(departId));
        if (b) {
            throw new BadRequestException(null, "department", "department.user.not.null");
        }
        departmentRepository.delete(department);
    }

    /**
     * 获取全部部门
     */
    public List<DepartmentResponse> findAllDepartment(String token) {
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        QDepartment qDepartment = QDepartment.department;
        Iterable<Department> iterable = departmentRepository.findAll(qDepartment.departCode.like(departmentModel.getDepartCode() + "%"));
        Type listType = new TypeToken<List<DepartmentResponse>>() {
        }.getType();
        return modelMapper.map(IterableUtils.toList(iterable), listType);
    }

    /**
     * 获取所有的分公司
     */
    public List<DepartmentResponse> findAllBranch() {
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(QDepartment.department.type.eq(DepartmentType.BRANCH)).and(QDepartment.department.status.eq(BaseStatus.ON));
        Iterable<Department> iterable = departmentRepository.findAll(booleanBuilder);
        Type listType = new TypeToken<List<DepartmentResponse>>() {
        }.getType();
        return modelMapper.map(IterableUtils.toList(iterable), listType);
    }
}
